<template>
  <div>
    <!-- 表头分页查询条件， shadow="never" 指定 card 卡片组件没有阴影 -->
    <el-card shadow="never" class="mb-5">
      <!-- flex 布局，内容垂直居中 -->
      <div class="flex items-center flex-col md:flex-row">
        <el-text>文章标题</el-text>
        <div class="ml-3 mb-2 w-52 mr-5 md:mb-0">
          <el-input v-model="searchArticleTitle" placeholder="请输入（模糊查询）" />
        </div>
        <el-text>创建日期</el-text>
        <div class="ml-1 w-30 mr-1 mb-2 md:ml-3 md:w-30 md:mr-5 md:mb-0">
          <!-- 日期选择组件（区间选择） -->
          <el-date-picker v-model="pickDate" type="daterange" style="width: 260px;" range-separator="至"
            start-placeholder="开始时间" end-placeholder="结束时间" size="default" :shortcuts="shortcuts"
            @change="datepickerChange" />
        </div>
        <div>
          <el-button type="primary" class="ml-3" :icon="Search" @click="getTableData">查询</el-button>
          <el-button class="ml-3" :icon="RefreshRight" @click="reset">重置</el-button>
        </div>
      </div>
    </el-card>
    <el-card shadow="never">
      <!-- 写文章按钮 -->
      <div class="mb-5">
        <el-button type="primary" @click="onWrite">
          <el-icon class="mr-1">
            <EditPen />
          </el-icon>
          写文章</el-button>
      </div>
      <!----------------- 写文章dialog弹框 ----------------->
      <el-dialog v-model="isArticlePublishEditorShow" :fullscreen="true" :show-close="false"
        :close-on-press-escape="false">
        <template #header="{ close, titleId, titleClass }">
          <!-- 固钉组件，固钉到顶部 -->
          <el-affix style="width: 100%;">
            <div class="flex h-10 bg-white">
              <!-- 字体加粗 -->
              <h4 class="font-bold">写文章</h4>
              <!-- 按钮靠右对齐 -->
              <div class="flex ml-auto">
                <el-popconfirm
                  @confirm="onSave"
                  @cancel="onExited"
                  :hide-after=0
                  width="220"
                  confirm-button-text="临时保存"
                  cancel-button-text="不保存"
                  :icon="InfoFilled"
                  icon-color="#626AEF"
                  title="是否临时保存？">
                  <template #reference>
                    <el-button>取消</el-button>
                  </template>
                </el-popconfirm>
                <el-button type="primary" @click="publishArticleSubmit">
                    <el-icon class="mr-1">
                      <Promotion />
                    </el-icon>
                    发布
                </el-button>
              </div>
            </div>
          </el-affix>
        </template>
        <!-- 文章表单 -->
        <el-form ref="publicArticleFormRef" :model="form" :rules="rules" label-position="top" size="large">
          <el-form-item label="标题" prop="title">
            <el-input v-model="form.title" placeholder="请输入文章标题" autocomplete="off" size="large" maxlength="40" show-word-limit clearable  />
          </el-form-item>
          <el-form-item label="内容" prop="content">
            <!-- Markdown 编辑器 -->
            <MdEditor v-model="form.content" @onUploadImg="onUploadImg" editorId="publishArticleEditor" />
          </el-form-item>
          <el-form-item label="封面" prop="cover">
            <el-upload class="avatar-uploader" action="#" :on-change="handleCoverChange" :auto-upload="false" :show-file-list="false">
              <img v-if="form.cover" :src="form.cover" class="avatar" />
              <el-icon v-else class="avatar-uploader-icon">
                <Plus />
              </el-icon>
            </el-upload>
          </el-form-item>
          <el-form-item label="摘要" prop="summary">
            <el-input v-model="form.summary" :rows="3" type="textarea" placeholder="请输入文章摘要，最多150个字" />
          </el-form-item>
          <el-form-item label="分类" prop="categoryId">
            <el-select v-model="form.categoryId" clearable placeholder="---请选择---" size="large">
              <el-option v-for="item in categories" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="标签" prop="tags">
            <el-select v-model="form.tags" placeholder="---请输入---" multiple filterable remote :reserve-keyword="false"
              remote-show-suffix :remote-method="remoteMethod" allow-create default-first-option
              :loading="tagSelectLoading" size="large">
              <el-option v-for="item in tags" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
          </el-form-item>
        </el-form>
      </el-dialog>
      <!---------------- 编辑文章dialog弹框 ---------------->
      <el-dialog v-model="isArticleUpdateEditorShow" :fullscreen="true" :show-close="false"
        :close-on-press-escape="false">
        <template #header="{ close, titleId, titleClass }">
          <!-- 固钉组件，固钉到顶部 -->
          <el-affix style="width: 100%;">
            <div class="flex h-10 bg-white">
              <!-- 字体加粗 -->
              <h4 class="font-bold">编辑文章</h4>
              <!-- 按钮靠右对齐 -->
              <div class="flex ml-auto">
                <el-button @click="isArticleUpdateEditorShow = false">取消</el-button> 
                <el-button type="primary" @click="updateSubmit">
                    <el-icon class="mr-1">
                      <Promotion />
                    </el-icon>
                    保存
                </el-button>
              </div>
            </div>
          </el-affix>
        </template>
        <!-- 文章表单 -->
        <el-form ref="updateArticleFormRef" :model="updateArticleForm" :rules="rules" label-position="top" size="large">
          <el-form-item label="标题" prop="title">
            <el-input v-model="updateArticleForm.title" placeholder="请输入文章标题" autocomplete="off" size="large" maxlength="40" show-word-limit clearable  />
          </el-form-item>
          <el-form-item label="内容" prop="content">
            <!-- Markdown 编辑器 -->
            <MdEditor v-model="updateArticleForm.content" @onUploadImg="onUploadImg" editorId="updateArticleEditor" />
          </el-form-item>
          <el-form-item label="封面" prop="cover">
            <el-upload class="avatar-uploader" action="#" :on-change="handleUpdateCoverChange" :auto-upload="false" :show-file-list="false">
              <img v-if="updateArticleForm.cover" :src="updateArticleForm.cover" class="avatar" />
              <el-icon v-else class="avatar-uploader-icon">
                <Plus />
              </el-icon>
            </el-upload>
          </el-form-item>
          <el-form-item label="摘要" prop="summary">
            <el-input v-model="updateArticleForm.summary" :rows="3" type="textarea" placeholder="请输入文章摘要，最多150个字" />
          </el-form-item>
          <el-form-item label="分类" prop="categoryId">
            <el-select v-model="updateArticleForm.categoryId" clearable placeholder="---请选择---" size="large">
              <el-option v-for="item in categories" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="标签" prop="tags">
            <el-select v-model="updateArticleForm.tags" placeholder="---请输入---" multiple filterable remote :reserve-keyword="false"
              remote-show-suffix :remote-method="remoteMethod" allow-create default-first-option
              :loading="tagSelectLoading" size="large">
              <el-option v-for="item in tags" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
          </el-form-item>
        </el-form>
      </el-dialog>
      <!-- 表格渲染列表 -->
      <el-table :data="tableData" border stripe style="width: 100%" v-loading="tableLoading">
        <el-table-column prop="id" label="ID" width="50" />
        <el-table-column prop="title" label="标题" width="300" />
        <el-table-column prop="cover" label="封面" width="180">
          <template #default="{ row }">
            <img v-if="row.cover" :src="row.cover" style="width: 100px;">
            <img v-else style="width: 100px;" src="@/assets/noPicture.png">
          </template>
        </el-table-column>
        <el-table-column prop="isTop" label="是否置顶" width="100">
          <template #default="{ row }">
            <el-switch
              @change="handleIsTopChange(row)"
              v-model="row.isTop"
              inline-prompt
              :active-icon="Check"
              :inactive-icon="Close"
            />
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="发布时间" width="180" />
        <el-table-column label="操作">
          <template #default="{ row }">
            <div class="flex flex-col items-center md:flex-row">
              <el-button class="mb-2 md:mb-0" size="small" @click="showArticleUpdateEditor(row)">
                <el-icon class="mr-1"><Edit /></el-icon>
                编辑
              </el-button>

              <el-button size="small" @click="goArticleDetailPage(row.id)">
                <el-icon class="mr-1"><View /></el-icon>
                预览
              </el-button>

              <el-button class="mr-3" type="danger" size="small" @click="deleteArticleSubmit(row)">
                <el-icon class="mr-1"><Delete /></el-icon>
                删除
              </el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页 -->
      <div class="mt-10 flex justify-center">
        <el-pagination v-model:current-page="current" v-model:page-size="size" :page-sizes="[10, 20, 50]" :small="false"
          :background="true" layout="total, sizes, prev, pager, next, jumper" :total="total"
          @size-change="handleSizeChange" @current-change="getTableData" />
      </div>
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onUnmounted } from 'vue'
import { Search, RefreshRight, Check, Close } from '@element-plus/icons-vue'
import moment from 'moment'
import { getArticlePageList, deleteArticle, publishArticle, getArticleDetail, updateArticle, updateArticleIsTop } from '@/api/admin/article'
import { showMessage, showModel } from '@/composables/util'
import { MdEditor } from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
import { uploadFile } from '@/api/admin/file'
import { getCategorySelectList } from '@/api/admin/category'
import { searchTags, getTagSelectList } from '@/api/admin/tag'
import { InfoFilled } from '@element-plus/icons-vue'
import { debounce } from 'lodash'; // 使用 lodash 的 debounce 函数
import { useRouter } from 'vue-router'


const router = useRouter()


// 模糊搜索的文章标题
const searchArticleTitle = ref('')
// 日期
const pickDate = ref('')
// 查询条件：开始时间和结束时间
const startDate = reactive({})
const endDate = reactive({})
// 监听日期的改变
const datepickerChange = (e) => {
  startDate.value = moment(e[0]).format('YYYY-MM-DD')
  endDate.value = moment(e[1]).format('YYYY-MM-DD')
}
// 添加快捷时间
const shortcuts = [
  {
    text: '最近一周',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
      return [start, end]
    },
  },
  {
    text: '最近一个月',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
      return [start, end]
    },
  },
  {
    text: '最近三个月',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
      return [start, end]
    },
  },
]
// 重置按钮
const reset = () => {
  searchArticleTitle.value = ''
  pickDate.value = ''
  startDate.value = null
  endDate.value = null
  getTableData()
}
// 表格加载 Loading
const tableLoading = ref(false)
// 表格数据
const tableData = ref([])
// 当前页码，给了一个默认值 1
const current = ref(1)
// 总数据量，给了个默认值 0
const total = ref(0)
// 每页显示的数据量，给了个默认值 10
const size = ref(10)

// 底部每页展示数量变化时
const handleSizeChange = (chooseSize) => {
  size.value = chooseSize
  // 重新获取分页数据
  getTableData()
}

// 获取文章分页列表
const getTableData = async () => {
  tableLoading.value = true
  const data = {
    title: searchArticleTitle.value,
    startDate: startDate.value,
    endDate: endDate.value,
    current: current.value,
    size: size.value,
    status: 0 // 后端定义0默认最新
  }
  const res = await getArticlePageList(data)
  if (res.success == true) {
    tableData.value = res.data,
      current.value = res.current,
      size.value = res.size,
      total.value = res.total
  }
  tableLoading.value = false
}
getTableData()



// 删除文章
const deleteArticleSubmit = async (row) => {
  await showModel('是否确定要删除该文章')
  const articleId = row.id
  const res = await deleteArticle(articleId)
  if (res.success == true) {
    showMessage('删除成功')
    getTableData()
  } else {
    showMessage(res.message, 'error')
  }
}

// 写文章dialog弹框是否可见
const isArticlePublishEditorShow = ref(false)

// 点击写文章 让dialog弹框显示
const onWrite = () => {
  isArticlePublishEditorShow.value = true
  // 获取文章分类
  getCategorySelect()
  // 获取标签
  getTagSelect()
}

// 发布文章form表单
const form = reactive({
  title: '',
  content: '请输入内容',
  cover: '',
  summary: '',
  categoryId: null,
  tags: []
})

// 发布文章表单引用
const publicArticleFormRef = ref(null)

// 发布文章校验规则
const rules = {
  title: [
    { required: true, message: '请输入文章标题', trigger: ['blur', 'change'] },
    { min: 1, max: 40, message: '文章标题要求大于1个字符，小于40个字符', trigger: ['blur', 'change'] },
  ],
  content: [{ required: true, message: '请输入文章内容', trigger: ['blur', 'change'] }],
  summary: [  
    { required: true, message: '请输入文章摘要', trigger: ['blur', 'change'] },  
    { min: 1, max: 150, message: '文章摘要要求不能超过150个字', trigger: ['blur', 'change'] },  
  ], 
  categoryId: [{ required: true, message: '请选择文章分类', trigger: ['blur', 'change'] }],
  tags: [{ required: true, message: '请选择文章标签', trigger: ['blur', 'change'] }],
}

// 发布文章-上传文章封面图片
const handleCoverChange = async (file) => {
  // 创建表单对象
  const formData = new FormData()
  // 添加file字段，传入文件
  formData.append('file', file.raw)
  const res = await uploadFile(formData)
  if (res.success == true) {
    // 把返回的图片路径设置到表单中的封面上
    form.cover = res.data.url
    showMessage('上传成功')
  } else {
    showMessage(res.message, 'error')
  }
}

// md编辑器图片上传
const onUploadImg = async (files, callback) => {
  const res = await Promise.all(
    files.map((file) => {
      return new Promise(async (rev, rej) => {
        const formData = new FormData()
        formData.append("file", file)
        const res = await uploadFile(formData)
        if (res.success == true) {
          // 调用 callback 函数，回显上传图片
          callback([res.data.url])
        }
      })
    })
  )
}

// 定义文章分类数组
const categories = ref([])
// 获取文章分类select
const getCategorySelect = async () => {
  const res = await getCategorySelectList()
  if (res.success == true) {
    categories.value = res.data
  }
}
// 获取标签列表select
const getTagSelect = async () => {
  const res = await getTagSelectList()
  if (res.success == true) {
    tags.value = res.data
  }
}

// 发布文章-获取标签 select Loading 状态，默认不显示
const tagSelectLoading = ref(false)
// 定义文章标签数组--查询后放的
const tags = ref([])

// 定义文章标签搜索防抖函数
const debounceFuntion = debounce(async (query) => {
  // 显示 loading
  tagSelectLoading.value = true
  const res = await searchTags(query)
  if (res.success == true) {
    // 将返回的标签设置到tags文章标签数组中
    tags.value = res.data
  }
  // 隐藏 loading
  tagSelectLoading.value = false
}, 1000)

// 发布文章-获取标签 根据用户输入的标签名称，远程模糊查询
const remoteMethod = (query) => {
  // 如果用户查询的关键词不为空
  if (query) {
    // 使用防抖函数
    debounceFuntion(query)
  }
}

// 在组件卸载时清除防抖函数的定时器  
onUnmounted(() => {
  // 如果存在防抖函数
  if(debounceFuntion) {
    debounceFuntion.cancel()
  }

})

// 临时保存内容
const onSave = () => {
  // 不需要清除内容 直接退出 关闭dialog弹框
  isArticlePublishEditorShow.value = false
}

// 清空内容退出
const onExited = () => {
  // 清空内容
  form.title = ''
  form.content = '请输入内容'
  form.cover = ''
  form.summary = ''
  // 将表单中已填的分类内容清除
  form.categoryId = null
  // 将表单中已填的标签内容清除
  form.tags = []
  // 将服务器返回的分类数据删除
  categories.value = []
  // 将远程搜索的标签数据删除
  tags.value = []
  // 关闭dialog弹框
  isArticlePublishEditorShow.value = false
}

// 点击发布文章
const publishArticleSubmit = async () => {
  await publicArticleFormRef.value.validate()
  const res = await publishArticle(form)
  if (res.success == true) {
    showMessage('发布成功')
    // 隐藏发布文章dialog弹框
    isArticlePublishEditorShow.value = false
    // 调用清空内容 隐藏dialog弹框 的方法
    onExited()
    // 重新请求分页接口，渲染列表数据
    getTableData()
  } else {
    showMessage(res.message, 'error')
  }
}

// ==========编辑文章功能===============
// 是否显示编辑文章dialog对话框
const isArticleUpdateEditorShow = ref(false)
// 编辑文章表单引用
const updateArticleFormRef = ref(null)
// 修改文章表单对象
const updateArticleForm = reactive({
    id: null,
    title: '',
    content: '请输入内容',
    cover: '',
    categoryId: null,
    tags: [],
    summary: ""
})

// 点击编辑文章
const showArticleUpdateEditor = async (row) => {
  // 显示编辑文章的dialog弹框
  isArticleUpdateEditorShow.value = true
  // 获取所有分类
  getCategorySelect()
  // 获取所有标签
  getTagSelect()
  // 拿到文章id
  const articleId = row.id
  // 根据文章id获取文章
  const res = await getArticleDetail(articleId)
  if (res.success == true) {
    // 把返回的数据设置到表单上
    updateArticleForm.id = res.data.id
    updateArticleForm.title = res.data.title
    updateArticleForm.cover = res.data.cover
    updateArticleForm.content = res.data.content
    updateArticleForm.categoryId = res.data.categoryId
    updateArticleForm.tags = res.data.tagIds
    updateArticleForm.summary = res.data.summary
  }
}


// 编辑文章--上传文章封面
const handleUpdateCoverChange = async (file) => {
  // 创建表单对象
  const formData = new FormData()
  // 添加 file 字段，并传入文件
  formData.append('file', file.raw)
  // 发送上传图片请求
  const res = await uploadFile(formData)
  if (res.success == true) {
    // 上传成功则替换表单中的封面链接
    updateArticleForm.cover = res.data.url
    showMessage('上传成功')
    console.log('成功了');
  } else {
    showMessage(res.message, 'error')
    console.log('失败了');
  }
}

// 保存更新文章
const updateSubmit = async () => {
  await updateArticleFormRef.value.validate()
  // 请求更新文章接口
  const res = await updateArticle(updateArticleForm)
  if (res.success == true) {
    showMessage('保存成功')
    // 隐藏dialog弹框
    isArticleUpdateEditorShow.value = false
    // 重新请求文章分页接口，渲染文章列表数据
    getTableData()
  } else {
    showMessage(res.message, 'error')
  }
}

// 预览文章--跳转文章详情页
const goArticleDetailPage = (articleId) => {
  router.push('/article/' + articleId)
}

// 点击置顶
const handleIsTopChange = async (row) => {
  const res = await updateArticleIsTop({id: row.id, isTop: row.isTop})
  if (res.success) {
    // 重新请求分页接口，渲染列表数据
    getTableData()
    showMessage(row.isTop ? "置顶成功" : "已取消置顶")
  } else {
    showMessage(res.message, 'error')
  }
}

</script>
<style scoped>
/* 封面图片样式 */
.avatar-uploader .avatar {
  width: 200px;
  height: 100px;
  display: block;
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 200px;
  height: 100px;
  text-align: center;
}

/* 指定 select 下拉框宽度 */
.el-select--large {
  width: 600px;
}
</style>
<style>
.md-editor-footer {
    height: 40px;
}
</style>